﻿Imports System.Data.Objects
Imports System.Data.Objects.DataClasses
Imports System.Reflection
Imports System.Runtime.Serialization
Imports System.Windows.Forms

Public Class Utility

    Public Shared Sub InitStatesGrid(ByVal grid As DataGridView, ByVal valuesDataSet As DataSet)
        ' collect state counts in a dictionary
        Dim dictStates As New Dictionary(Of String, Integer)
        For Each table As DataTable In valuesDataSet.Tables
            AddStatesToDictionary(table, dictStates)
        Next

        ' pivot the dictionary into a datatable
        Dim dsStates As New DataSet()
        dsStates.Tables.Add(New DataTable())
        Dim statesTable As DataTable = dsStates.Tables(0)
        For Each state As String In dictStates.Keys
            statesTable.Columns.Add(state)
        Next
        Dim stateRow As DataRow = statesTable.NewRow()
        For Each state As String In dictStates.Keys
            stateRow(state) = dictStates(state)
        Next
        statesTable.Rows.Add(stateRow)

        grid.DataSource = statesTable
        ' without pivot
        'grid.DataSource = (From x In ds.Tables(Constants.TABLE_VALUES) _
        '                            Group x By State = x.Item(0) Into Count() _
        '                            Select State, Count = Count).ToList()
        grid.ClearSelection() ' useless?
        For Each column As DataGridViewColumn In grid.Columns
            column.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
        Next
    End Sub

    Public Shared Function GetContextFromEntity(ByVal entity As EntityObject) As ObjectContext
        If entity Is Nothing Then
            Throw New ArgumentNullException("entity")
        End If
        Dim entityWithRelation As IEntityWithRelationships = TryCast(entity, IEntityWithRelationships)
        If (entityWithRelation Is Nothing) Then
            Throw New Exception("No relationships found")
        End If

        If (Not entityWithRelation.RelationshipManager.GetAllRelatedEnds().Any()) Then
            Throw New Exception("No relationships found")
        End If

        Dim foundUnusableRelatedEnd As Boolean = False

        For Each relatedEnd As IRelatedEnd In entityWithRelation.RelationshipManager.GetAllRelatedEnds()

            Dim query As ObjectQuery = Nothing
            Try
                Dim sourceQuery As IEnumerable = relatedEnd.CreateSourceQuery()
                query = TryCast(sourceQuery, ObjectQuery)
            Catch ex As Exception
                foundUnusableRelatedEnd = True
                Continue For
            End Try

            If query IsNot Nothing Then
                Return query.Context
            End If
            foundUnusableRelatedEnd = True
            Continue For
        Next

        If (foundUnusableRelatedEnd) Then
            Throw New Exception("The entity is added or detached")
        Else
            Throw New Exception("Entity context not found")
        End If

    End Function

    Public Shared Function GetPropertyInfos(entity As Object) As List(Of PropertyInfo)
        Return (From p In entity.GetType().GetProperties() _
                               Where Attribute.IsDefined(p, GetType(DataMemberAttribute))) _
                            .ToList()
    End Function

    Public Shared Function GetStateFromEntity(ByVal entity As Object) As String
        ' use reflection because the objects are generated from T4 templates
        Dim changetrackerProperty As PropertyInfo = entity.GetType().GetProperty("ChangeTracker")
        If (changetrackerProperty Is Nothing) Then Return "Unknown"
        Dim changetracker As Object = changetrackerProperty.GetValue(entity, Nothing)
        If (changetracker Is Nothing) Then Return "Unknown"
        Dim stateProperty As PropertyInfo = changetracker.GetType().GetProperty("State")
        If (stateProperty Is Nothing) Then Return "Unknown"
        Dim stateValue As Object = stateProperty.GetValue(changetracker, Nothing)
        If (stateValue Is Nothing) Then Return "Unknown"
        Return stateValue.ToString()
    End Function

    Public Shared Function IsPropertyChanged(ByVal entity As Object, propertyName As String) As Boolean
        ' use reflection because the objects are generated from T4 templates
        Dim changetrackerProperty As PropertyInfo = entity.GetType().GetProperty("ChangeTracker")
        If (changetrackerProperty Is Nothing) Then Return False
        Dim changetracker As Object = changetrackerProperty.GetValue(entity, Nothing)
        If (changetracker Is Nothing) Then Return False

        Dim originalValuesProperty As PropertyInfo = changetracker.GetType().GetProperty("OriginalValues")
        If (originalValuesProperty Is Nothing) Then Return False
        Dim originalValues As Object = originalValuesProperty.GetValue(changetracker, Nothing)
        If (originalValues Is Nothing) Then Return False

        Dim containsKeyMethod As MethodInfo = originalValues.GetType().GetMethod("ContainsKey")
        If (containsKeyMethod Is Nothing) Then Return False
        Dim containsKeyObject As Object = containsKeyMethod.Invoke(originalValues, New Object() {propertyName})
        If (containsKeyObject Is Nothing) Then Return False
        Return CBool(containsKeyObject)
    End Function

    Public Shared Function GetOriginalValue(ByVal entity As Object, propertyName As String) As Object
        If (Not IsPropertyChanged(entity, propertyName)) Then
            Return "Unchanged"
        End If
        ' use reflection because the objects are generated from T4 templates
        Dim changetrackerProperty As PropertyInfo = entity.GetType().GetProperty("ChangeTracker")
        If (changetrackerProperty Is Nothing) Then Return "Unchanged"
        Dim changetracker As Object = changetrackerProperty.GetValue(entity, Nothing)
        If (changetracker Is Nothing) Then Return False

        Dim originalValuesProperty As PropertyInfo = changetracker.GetType().GetProperty("OriginalValues")
        If (originalValuesProperty Is Nothing) Then Return "Unchanged"
        Dim originalValues As Object = originalValuesProperty.GetValue(changetracker, Nothing)
        If (originalValues Is Nothing) Then Return "Unchanged"

        Dim dict As IDictionary(Of String, Object) = TryCast(originalValues, IDictionary(Of String, Object))
        If (dict Is Nothing) Then Return "Unchanged"
        Return dict(propertyName)
    End Function

    Public Shared Function NullableObjectToString(obj As Object) As String
        If (obj Is Nothing) Then Return String.Empty
        Return obj.ToString()
    End Function

#Region "Private methods"

    Private Shared Sub AddStatesToDictionary(ByVal dt As DataTable, ByVal dictStates As Dictionary(Of String, Integer))
        For Each row As DataRow In dt.Rows
            ' first column contains the states
            Dim state As String = row.Item(Constants.COLUMN_STATE).ToString()
            If (dictStates.Keys.Contains(state)) Then
                dictStates(state) = Convert.ToInt32(dictStates(state)) + 1
            Else
                dictStates(state) = 1
            End If
        Next
    End Sub

#End Region

End Class
